﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Web.UI;

namespace IRC.IRepairClouds.WebClient
{
    //[DebuggerDisplay(@"\{{CompleteUrl}}")]
    public class UrlParser : IEquatable<UrlParser>
    {
        public string CompleteUrl { get; set; }
        public string Url { get; set; }
        public string Anchor { get; set; }

        public Dictionary<string, string> Queries { get; private set; }
        public Dictionary<string, string> AQueries { get; private set; }

        public UrlParser()
        {
            Queries = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
            AQueries = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
        }

        public UrlParser(string completeUrl)
        {
            Load(completeUrl);
        }

        public void Load(Page page)
        {
            //page.ThrowIfNull("page");
            Load(page.Request.Url.AbsoluteUri);
        }

        private Dictionary<string, string> ParseQuery(string query)
        {
            var isNamePart = true;
            var name = new StringBuilder();
            var value = new StringBuilder();

            var res = new Dictionary<string, string>();
            string sn;

            for (var i = 0; i < query.Length; i++)
            {
                var ch = query[i];
                if (ch == '=')
                    isNamePart = false;
                else if (ch == '&')
                {
                    sn = name.ToString();
                    if (!string.IsNullOrEmpty(sn) && !res.ContainsKey(sn))
                        res.Add(sn, value.ToString());

                    isNamePart = true;
                    name.Clear();
                    value.Clear();
                }
                else
                {
                    if (isNamePart)
                        name.Append(ch);
                    else
                        value.Append(ch);
                }
            }
            sn = name.ToString();
            if (!string.IsNullOrEmpty(sn) && !res.ContainsKey(sn))
                res.Add(sn, value.ToString());
            return res;
        }

        public void Load(string completeUrl)
        {
            //completeUrl.ThrowIfNull("completeUrl");

            CompleteUrl = completeUrl;
            int pq = completeUrl.IndexOf('?');
            int pa = completeUrl.IndexOf('#', pq + 1);
            int paq = completeUrl.IndexOf('?', pa + 1);
            Url = string.Empty;
            string query = string.Empty;
            Anchor = string.Empty;
            string aquery = string.Empty;

            Url = completeUrl.Substring(0, pq != -1 ? pq : completeUrl.Length);
            if (pq != -1)
                query = completeUrl.Substring(pq + 1, pa != -1 ? pa - pq - 1 : completeUrl.Length - pq - 1);
            if (pa != -1)
            {
                Anchor = completeUrl.Substring(pa + 1, paq != -1 ? paq - pa - 1 : completeUrl.Length - pa - 1);
                if (paq != -1)
                    aquery = completeUrl.Substring(paq + 1);
            }
            Queries = this.ParseQuery(query);
            AQueries = this.ParseQuery(aquery);
        }

        public override int GetHashCode()
        {
            return CompleteUrl.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            UrlParser other = obj as UrlParser;
            if (other == null)
                return false;
            return Equals(other);
        }

        public bool Equals(UrlParser other)
        {
            if (
                this.Url.ToLowerInvariant() == other.Url.ToLowerInvariant() &&
                this.Anchor.ToLowerInvariant() == other.Anchor.ToLowerInvariant() &&
                this.Queries.Count == other.Queries.Count &&
                this.AQueries.Count == other.AQueries.Count)
            {

                foreach (var i in this.Queries)
                {
                    string val;
                    if (!other.Queries.TryGetValue(i.Key, out val) || i.Value.ToLowerInvariant() != val.ToLowerInvariant())
                        return false;
                }
                foreach (var i in this.AQueries)
                {
                    string val;
                    if (!other.AQueries.TryGetValue(i.Key, out val) || i.Value.ToLowerInvariant() != val.ToLowerInvariant())
                        return false;
                }
                return true;
            }
            return false;
        }
    }

}